// 1 <= C <= 1000
// 1 <= M, N, a, b, m, seed0 <= 20000

#include "pthread.h"
#include <stdio.h>
#include <string.h>

#if defined(WIN32) || defined(WIN64)
    #include <windows.h>
    #pragma comment(lib, "kernel32.lib")
#else /* !defined(WIN32) && !defined(WIN64) */
    #include <unistd.h>
#endif /* defined(WIN32) || defined(WIN64) */


template<typename T>
class TSStack
{
public:
    TSStack() : m_count(0)
    {
        pthread_spin_init(&m_lock, 0);
    }

    void push(T& element)
    {
        pthread_spin_lock(&m_lock);
        m_storage[m_count] = element;
        ++m_count;
        pthread_spin_unlock(&m_lock);
    }

    bool pop(T& element)
    {
        pthread_spin_lock(&m_lock);
        if (m_count == 0)
        {
            pthread_spin_unlock(&m_lock);
            return false;
        }
        element = m_storage[m_count - 1];
        --m_count;
        pthread_spin_unlock(&m_lock);
        return true;
    }
private:
    T m_storage[3000];
    int m_count;
    pthread_spinlock_t m_lock;
};


unsigned int GetNumberOfCores(void)
{
    unsigned int numberOfCores = 1;

#if defined(WIN32) || defined(WIN64)

    SYSTEM_INFO sysInfo;

    GetSystemInfo(&sysInfo);

    numberOfCores = sysInfo.dwNumberOfProcessors;

#else /* !defined(WIN32) && !defined(WIN64) */

#ifdef _SC_NPROCESSORS_CONF
    numberOfCores = sysconf(_SC_NPROCESSORS_CONF);
#endif /* _SC_NPROCESSORS_CONF */
    if (1 > numberOfCores)
    {
        numberOfCores = 1;
    }

#endif /* defined(WIN32) || defined(WIN64) */

    return numberOfCores;
}

#define POS_ITER(currMaxt, to, from, res)\
currMaxt.m_sum += *to - *from;\
if (currMaxt.m_sum < 0)\
{\
   currMaxt.m_sum = 0;\
   currMaxt.m_beginPtr = to + 1;\
}\
else if (currMaxt.m_sum > res.m_sum)\
{\
   res = currMaxt;\
   res.m_endPtr = to;\
}


#define NEG_ITER(currMaxt, to, from, res)\
currMaxt.m_sum += *to - *from;\
if (currMaxt.m_sum > res.m_sum)\
{\
   res = currMaxt;\
   res.m_endPtr = to;\
}\
if (currMaxt.m_sum < 0)\
{\
   currMaxt.m_sum = 0;\
   currMaxt.m_beginPtr = to + 1;\
}

struct Task;

typedef void (*TaskFunc)(int, Task&) ; // input int parameter - thread number

void initialTask(int, Task&);

struct ResultStruct
{
    ResultStruct(): m_ulColumn(-1), m_ulRow(-1), m_brColumn(-1), m_brRow(-1), m_sum(-2000000000)
    {}
    ResultStruct(short ulColumn, short ulRow, short brColumn, short brRow, short sum): m_ulColumn(ulColumn), m_ulRow(ulRow), m_brColumn(brColumn), m_brRow(brRow), m_sum(sum)
    {
    }
    short m_ulColumn; // Upper Left Column
    short m_ulRow;    // Upper Left Row
    short m_brColumn; // Bottom Right Column
    short m_brRow;    // Bottom Right Row
    int m_sum;
};

struct TempResultStruct
{
    TempResultStruct(int* beginPtr, int* endPtr, int width, int sum)
      : m_beginPtr(beginPtr)
      , m_endPtr(endPtr)
      , m_sum(sum)
      , m_width(width)
    {}
    int* m_beginPtr;
    int* m_endPtr;
    int m_sum;
    int m_width;
};


struct TestCaseData
{
    int M, N, a, b, m, seed0;
    int matrixNumber; //in matrixes array
    pthread_spinlock_t m_lock;
    int countedColumnSet;
    bool isTrans;
};

struct Task
{
    enum TaskType
    {
        COMBINED,
        PAIRED,
        SINGLE
    };
    TaskType m_columnTaskType;
    TaskFunc m_func;
    short m_columns[8];
    short m_testCase;
    unsigned char m_columnsCount;
};

struct ThreadContext
{
    int m_number;
    TSStack<Task> m_tasks;
    ResultStruct m_testCasesResults[1000];
};

const int MAX_COLUMNS_NUMBER = 20000;
const int DATA_SIZE = MAX_COLUMNS_NUMBER * (MAX_COLUMNS_NUMBER + 1); // don't forget space for "zero" column
const int MAX_CONCURRENT_CASES = 20;
const int MAX_THREAD_NUMBER = 40;

ThreadContext threadsContext[MAX_THREAD_NUMBER];
unsigned int numCores = 0;
bool workDone = false;
int *matrixes[MAX_CONCURRENT_CASES] = {0};
int concurrentCases=1;
int T;// number of test cases
int casesLaunched = 0;
int casesDone = 0;
TestCaseData testCases[1000];
pthread_spinlock_t taskCountLock;
pthread_spinlock_t taskCountDoneLock;

void printMatrix(int* mat, int m, int n)
{
    for (int i = 0; i < 20; ++i)
    {
        for (int j = 0; j < 20; ++j)
        {
            printf("%d\t", mat[j * m + i]);
        }
        printf("%d\n", mat[(n - 1) * m + i]);
    }
    printf("\n");
}

void calcColumn(int * mat, int M, int fromIndex, int width, ResultStruct & result)
{
    int * to = &mat[(fromIndex + width - 1) * M];
    int *orig = to + M;
    int* from = &mat[(fromIndex - 1) * M];
    //fromIndex, 0, fromIndex + width - 1, 0, 0);
    TempResultStruct currMax(to, to, width, 0);
    TempResultStruct res(0, 0, 0, result.m_sum);
    if (res.m_sum > 0)
    {
       for (; to < orig; ++from, ++to)
       {
           POS_ITER(currMax, to, from, res)
       }
    }
    else
    {
       for (; to < orig; ++from, ++to)
       {
           NEG_ITER(currMax, to, from, res)
       }
    }
    if (res.m_sum > result.m_sum)
    {
       result.m_sum = res.m_sum;
       result.m_brColumn = (res.m_beginPtr - mat) / M;
       result.m_ulColumn = result.m_brColumn - res.m_width + 1;
       result.m_ulRow = (res.m_beginPtr - mat) % M;
       result.m_brRow = (res.m_endPtr - mat) % M;
    }
}

void calcColumnPaired(int * mat, int M, int fromIndex, int width1, int width2, ResultStruct & result)
{
   int * to1 = &mat[(fromIndex + width1 - 1) * M];
   int *orig = to1 + M;
   int * to2 = &mat[(fromIndex + width2 - 1) * M];
   int* from = &mat[(fromIndex - 1) * M];
   TempResultStruct currMax1(to1, to1, width1, 0);
   TempResultStruct currMax2(to2, to2, width2, 0);
   TempResultStruct res(0, 0, 0, result.m_sum);
   if (res.m_sum > 0)
   {
      for (; to1 < orig; ++from, ++to1, ++to2)
      {
         POS_ITER(currMax1, to1, from, res)
         POS_ITER(currMax2, to2, from, res)
      }
   }
   else
   {
      for (;  to1 < orig; ++from, ++to1, ++to2)
      {
         NEG_ITER(currMax1, to1, from, res)
         NEG_ITER(currMax2, to2, from, res)
      }
   }
   if (res.m_sum > result.m_sum)
   {
      result.m_sum = res.m_sum;
      result.m_brColumn = (res.m_beginPtr - mat) / M;
      result.m_ulColumn = result.m_brColumn - res.m_width + 1;
      result.m_ulRow = (res.m_beginPtr - mat) % M;
      result.m_brRow = (res.m_endPtr - mat)  % M;
   }
}

void calcColumnPaired(int * mat, int M, int fromIndex, int width1, int width2, int width3, ResultStruct & result)
{
   int * to1 = &mat[(fromIndex + width1 - 1) * M];
   int * orig = to1 + M;
   int * to2 = &mat[(fromIndex + width2 - 1) * M];
   int * to3 = &mat[(fromIndex + width3 - 1) * M];
   int* from = &mat[(fromIndex - 1) * M];
   TempResultStruct currMax1(to1, to1, width1, 0);
   TempResultStruct currMax2(to2, to2, width2, 0);
   TempResultStruct currMax3(to3, to3, width3, 0);
   TempResultStruct res(0, 0, 0, result.m_sum);
   if (res.m_sum > 0)
   {
      for (; to1 < orig; ++from, ++to1, ++to2, ++to3)
      {
         POS_ITER(currMax1, to1, from, res)
         POS_ITER(currMax2, to2, from, res)
         POS_ITER(currMax3, to3, from, res)
      }
   }
   else
   {
      for (; to1 < orig; ++from, ++to1, ++to2, ++to3)
      {
         NEG_ITER(currMax1, to1, from, res)
         NEG_ITER(currMax2, to2, from, res)
         NEG_ITER(currMax3, to3, from, res)
      }
   }
   if (res.m_sum > result.m_sum)
   {
      result.m_sum = res.m_sum;
      result.m_brColumn = (res.m_beginPtr - mat) / M;
      result.m_ulColumn = result.m_brColumn - res.m_width + 1;
      result.m_ulRow = (res.m_beginPtr - mat)  % M;
      result.m_brRow = (res.m_endPtr - mat)  % M;
   }
}


void calcColumnPaired(int * mat, int M, int fromIndex, int width1, int width2, int width3, int width4, ResultStruct & result)
{
    int * to1 = &mat[(fromIndex + width1 - 1) * M];
    int * orig = to1 + M;
    int * to2 = &mat[(fromIndex + width2 - 1) * M];
    int * to3 = &mat[(fromIndex + width3 - 1) * M];
    int * to4 = &mat[(fromIndex + width4 - 1) * M];    
    int* from = &mat[(fromIndex - 1) * M];
    TempResultStruct currMax1(to1, to1, width1, 0);
    TempResultStruct currMax2(to2, to2, width2, 0);
    TempResultStruct currMax3(to3, to3, width3, 0);
    TempResultStruct currMax4(to4, to4, width4, 0);
    TempResultStruct res(0, 0, 0, result.m_sum);
    if (res.m_sum > 0)
    {
        for (; to1 < orig; ++from, ++to1, ++to2, ++to3, ++to4) 
        {
            POS_ITER(currMax1, to1, from, res)
            POS_ITER(currMax2, to2, from, res)
            POS_ITER(currMax3, to3, from, res)
            POS_ITER(currMax4, to4, from, res)
        }
    }
    else
    {
        for (; to1 < orig; ++from, ++to1, ++to2, ++to3, ++to4)
        {
           NEG_ITER(currMax1, to1, from, res)
           NEG_ITER(currMax2, to2, from, res)
           NEG_ITER(currMax3, to3, from, res)
           NEG_ITER(currMax4, to4, from, res)
        }
    }
    if (res.m_sum > result.m_sum)
    {
       result.m_sum = res.m_sum;
       result.m_brColumn = (res.m_beginPtr - mat) / M;
       result.m_ulColumn = result.m_brColumn - res.m_width + 1;
       result.m_ulRow = (res.m_beginPtr - mat)  % M;
       result.m_brRow = (res.m_endPtr - mat)  % M;
    }
}

void calcColumnPaired(int * mat, int M, int fromIndex, int width1, int width2, int width3, int width4, int width5, ResultStruct & result)
{
   int * to1 = &mat[(fromIndex + width1 - 1) * M];
   int * orig = to1 + M;
   int * to2 = &mat[(fromIndex + width2 - 1) * M];
   int * to3 = &mat[(fromIndex + width3 - 1) * M];
   int * to4 = &mat[(fromIndex + width4 - 1) * M];    
   int * to5 = &mat[(fromIndex + width5 - 1) * M];    
   int* from = &mat[(fromIndex - 1) * M];
   TempResultStruct currMax1(to1, to1, width1, 0);
   TempResultStruct currMax2(to2, to2, width2, 0);
   TempResultStruct currMax3(to3, to3, width3, 0);
   TempResultStruct currMax4(to4, to4, width4, 0);
   TempResultStruct currMax5(to5, to5, width5, 0);
   TempResultStruct res(0, 0, 0, result.m_sum);
   if (res.m_sum > 0)
   {
      for (; to1 < orig; ++from, ++to1, ++to2, ++to3, ++to4, ++to5)
      {
         POS_ITER(currMax1, to1, from, res)
         POS_ITER(currMax2, to2, from, res)
         POS_ITER(currMax3, to3, from, res)
         POS_ITER(currMax4, to4, from, res)
         POS_ITER(currMax5, to5, from, res)
       }
   }
   else
   {
      for (; to1 < orig; ++from, ++to1, ++to2, ++to3, ++to4, ++to5)
      {
         NEG_ITER(currMax1, to1, from, res)
         NEG_ITER(currMax2, to2, from, res)
         NEG_ITER(currMax3, to3, from, res)
         NEG_ITER(currMax4, to4, from, res)
         NEG_ITER(currMax5, to5, from, res)
      }
   }
   if (res.m_sum > result.m_sum)
   {
      result.m_sum = res.m_sum;
      result.m_brColumn = (res.m_beginPtr - mat) / M;
      result.m_ulColumn = result.m_brColumn - res.m_width + 1;
      result.m_ulRow = (res.m_beginPtr - mat)  % M;
      result.m_brRow = (res.m_endPtr - mat)  % M;
   }
}


void calcColumnPaired(int * mat, int M, int fromIndex, int width1, int width2, int width3, int width4, int width5, int width6, ResultStruct & result)
{
   int * to1 = &mat[(fromIndex + width1 - 1) * M];
   int * orig = to1 + M;
   int * to2 = &mat[(fromIndex + width2 - 1) * M];
   int * to3 = &mat[(fromIndex + width3 - 1) * M];
   int * to4 = &mat[(fromIndex + width4 - 1) * M];    
   int * to5 = &mat[(fromIndex + width5 - 1) * M];    
   int * to6 = &mat[(fromIndex + width6 - 1) * M];    
   int* from = &mat[(fromIndex - 1) * M];
   TempResultStruct currMax1(to1, to1, width1, 0);
   TempResultStruct currMax2(to2, to2, width2, 0);
   TempResultStruct currMax3(to3, to3, width3, 0);
   TempResultStruct currMax4(to4, to4, width4, 0);
   TempResultStruct currMax5(to5, to5, width5, 0);
   TempResultStruct currMax6(to6, to6, width6, 0);
   TempResultStruct res(0, 0, 0, result.m_sum);
   if (res.m_sum > 0)
   {
      for (; to1 < orig; ++from, ++to1, ++to2, ++to3, ++to4, ++to5, ++to6)
      {
         POS_ITER(currMax1, to1, from, res)
         POS_ITER(currMax2, to2, from, res)
         POS_ITER(currMax3, to3, from, res)
         POS_ITER(currMax4, to4, from, res)
         POS_ITER(currMax5, to5, from, res)
         POS_ITER(currMax6, to6, from, res)
      }
   }
   else
   {
      for (; to1 < orig; ++from, ++to1, ++to2, ++to3, ++to4, ++to5, ++to6)
      {
         NEG_ITER(currMax1, to1, from, res)
         NEG_ITER(currMax2, to2, from, res)
         NEG_ITER(currMax3, to3, from, res)
         NEG_ITER(currMax4, to4, from, res)
         NEG_ITER(currMax5, to5, from, res)
         NEG_ITER(currMax6, to6, from, res)
      }
   }
   if (res.m_sum > result.m_sum)
   {
      result.m_sum = res.m_sum;
      result.m_brColumn = (res.m_beginPtr - mat) / M;
      result.m_ulColumn = result.m_brColumn - res.m_width + 1;
      result.m_ulRow = (res.m_beginPtr - mat)  % M;
      result.m_brRow = (res.m_endPtr - mat)  % M;
   }
}


void calcColumnPaired(int * mat, int M, int fromIndex, int width1, int width2, int width3, int width4, int width5, int width6, int width7, ResultStruct & result)
{
   int * to1 = &mat[(fromIndex + width1 - 1) * M];
   int * orig = to1 + M;
   int * to2 = &mat[(fromIndex + width2 - 1) * M];
   int * to3 = &mat[(fromIndex + width3 - 1) * M];
   int * to4 = &mat[(fromIndex + width4 - 1) * M];    
   int * to5 = &mat[(fromIndex + width5 - 1) * M];    
   int * to6 = &mat[(fromIndex + width6 - 1) * M];
   int * to7 = &mat[(fromIndex + width7 - 1) * M];    
   int* from = &mat[(fromIndex - 1) * M];
   TempResultStruct currMax1(to1, to1, width1, 0);
   TempResultStruct currMax2(to2, to2, width2, 0);
   TempResultStruct currMax3(to3, to3, width3, 0);
   TempResultStruct currMax4(to4, to4, width4, 0);
   TempResultStruct currMax5(to5, to5, width5, 0);
   TempResultStruct currMax6(to6, to6, width6, 0);
   TempResultStruct currMax7(to7, to7, width7, 0);
   TempResultStruct res(0, 0, 0, result.m_sum);
   if (res.m_sum > 0)
   {
      for (; to1 < orig; ++from, ++to1, ++to2, ++to3, ++to4, ++to5, ++to6, ++to7)
      {
         POS_ITER(currMax1, to1, from, res)
            POS_ITER(currMax2, to2, from, res)
            POS_ITER(currMax3, to3, from, res)
            POS_ITER(currMax4, to4, from, res)
            POS_ITER(currMax5, to5, from, res)
            POS_ITER(currMax6, to6, from, res)
            POS_ITER(currMax7, to7, from, res)
      }
   }
   else
   {
      for (; to1 < orig; ++from, ++to1, ++to2, ++to3, ++to4, ++to5, ++to6, ++to7)
      {
         NEG_ITER(currMax1, to1, from, res)
            NEG_ITER(currMax2, to2, from, res)
            NEG_ITER(currMax3, to3, from, res)
            NEG_ITER(currMax4, to4, from, res)
            NEG_ITER(currMax5, to5, from, res)
            NEG_ITER(currMax6, to6, from, res)
            NEG_ITER(currMax7, to7, from, res)
      }
   }
   if (res.m_sum > result.m_sum)
   {
      result.m_sum = res.m_sum;
      result.m_brColumn = (res.m_beginPtr - mat) / M;
      result.m_ulColumn = result.m_brColumn - res.m_width + 1;
      result.m_ulRow = (res.m_beginPtr - mat)  % M;
      result.m_brRow = (res.m_endPtr - mat)  % M;
   }
}



void calcColumnCombined(int * mat, int M, int fromIndex, int width1, int width2, ResultStruct & result)
{
   int * to = &mat[(fromIndex + width1 + width2 - 1) * M];
   int * orig = to + M;
   int* from = &mat[(fromIndex - 1) * M];
   int* middle = &mat[(fromIndex + width1 - 1) * M];
   TempResultStruct currMax1(middle, middle, width1, 0);
   TempResultStruct currMax2(to, to, width2, 0);
   TempResultStruct currMax3(to, to, width1 + width2, 0);
   TempResultStruct res(0, 0, 0, result.m_sum);
   if (res.m_sum > 0)
   {
      for (; to < orig; ++from, ++to, ++middle)
      {
         POS_ITER(currMax1, middle, from, res)
         POS_ITER(currMax2, to, middle, res)
         POS_ITER(currMax3, to, from, res)
      }
   }
   else
   {
      for (; to < orig; ++from, ++to, ++middle)
      {
         NEG_ITER(currMax1, middle, from, res)
         NEG_ITER(currMax2, to, middle, res)
         NEG_ITER(currMax3, to, from, res)
      }
   }
   if (res.m_sum > result.m_sum)
   {
      result.m_sum = res.m_sum;
      result.m_brColumn = (res.m_beginPtr - mat) / M;
      result.m_ulColumn = result.m_brColumn - res.m_width + 1;
      result.m_ulRow = (res.m_beginPtr - mat)  % M;
      result.m_brRow = (res.m_endPtr - mat)  % M;
   }
}


void calcColumnCombined(int * mat, int M, int fromIndex, int width1, int width2, int width3, ResultStruct & result)
{
    int * to = &mat[(fromIndex + width1 + width2 + width3 - 1) * M];
    int * orig = to + M;
    int* from = &mat[(fromIndex - 1) * M];
    int* middle1 = &mat[(fromIndex + width1 - 1) * M];
    int* middle2 = &mat[(fromIndex + width1 + width2 - 1) * M];
    TempResultStruct currMax1(middle1, middle1, width1, 0);
    TempResultStruct currMax2(middle2, middle2, width2, 0);
    TempResultStruct currMax3(middle2, middle2, width1 + width2, 0);
    TempResultStruct currMax4(to, to, width3, 0);
    TempResultStruct currMax5(to, to, width2 + width3, 0);
    TempResultStruct currMax6(to, to, width1 + width2 + width3, 0);
    TempResultStruct res(0, 0, 0, result.m_sum);
    if (res.m_sum > 0)
    {
        for (; to < orig; ++from, ++to, ++middle1, ++middle2)
        {
            POS_ITER(currMax1, middle1, from, res)
            POS_ITER(currMax2, middle2, middle1, res)
            POS_ITER(currMax3, middle2, from, res)
            POS_ITER(currMax4, to, middle2, res)
            POS_ITER(currMax5, to, middle1, res)
            POS_ITER(currMax6, to, from, res)
        }
    }
    else
    {
       for (; to < orig; ++from, ++to, ++middle1, ++middle2)
       {
          NEG_ITER(currMax1, middle1, from, res)
          NEG_ITER(currMax2, middle2, middle1, res)
          NEG_ITER(currMax3, middle2, from, res)
          NEG_ITER(currMax4, to, middle2, res)
          NEG_ITER(currMax5, to, middle1, res)
          NEG_ITER(currMax6, to, from, res)
       }
    }
    if (res.m_sum > result.m_sum)
    {
       result.m_sum = res.m_sum;
       result.m_brColumn = (res.m_beginPtr - mat) / M;
       result.m_ulColumn = result.m_brColumn - res.m_width + 1;
       result.m_ulRow = (res.m_beginPtr - mat)  % M;
       result.m_brRow = (res.m_endPtr - mat)  % M;
    }
}

void calcColumnCombined(int * mat, int M, int fromIndex, int width1, int width2, int width3, int width4, ResultStruct & result)
{
   int* from = &mat[(fromIndex - 1) * M];
   int* middle1 = &mat[(fromIndex + width1 - 1) * M];
   int* middle2 = &mat[(fromIndex + width1 + width2 - 1) * M];
   int* middle3 = &mat[(fromIndex + width1 + width2 + width3 - 1) * M];
   int* to = &mat[(fromIndex + width1 + width2 + width3 +width4 - 1) * M];
   int * orig = to + M;
   TempResultStruct currMax1(middle1, middle1, width1, 0);
   TempResultStruct currMax2(middle2, middle2, width2, 0);
   TempResultStruct currMax3(middle2, middle2, width1 + width2, 0);
   TempResultStruct currMax4(middle3, middle3, width3, 0);
   TempResultStruct currMax5(middle3, middle3, width2 + width3, 0);
   TempResultStruct currMax6(middle3, middle3, width1 + width2 + width3, 0);
   TempResultStruct currMax7(to, to, width4, 0);
   TempResultStruct currMax8(to, to, width3 + width4, 0);
   TempResultStruct currMax9(to, to, width2 + width3 + width4, 0);
   TempResultStruct currMax10(to, to, width1 + width2 + width3 + width4, 0);
   TempResultStruct res(0, 0, 0, result.m_sum);
   if (res.m_sum > 0)
   {
      for (; to < orig; ++from, ++to, ++middle1, ++middle2, ++middle3)
      {
         POS_ITER(currMax1, middle1, from, res)
         POS_ITER(currMax2, middle2, middle1, res)
         POS_ITER(currMax3, middle2, from, res)
         POS_ITER(currMax4, middle3, middle2, res)
         POS_ITER(currMax5, middle3, middle1, res)
         POS_ITER(currMax6, middle3, from, res)
         POS_ITER(currMax7, to, middle3, res)
         POS_ITER(currMax8, to, middle2, res)
         POS_ITER(currMax9, to, middle1, res)
         POS_ITER(currMax10, to, from, res)
      }
   }
   else
   {
      for (; to < orig; ++from, ++to, ++middle1, ++middle2, ++middle3)
      {
         NEG_ITER(currMax1, middle1, from, res)
         NEG_ITER(currMax2, middle2, middle1, res)
         NEG_ITER(currMax3, middle2, from, res)
         NEG_ITER(currMax4, middle3, middle2, res)
         NEG_ITER(currMax5, middle3, middle1, res)
         NEG_ITER(currMax6, middle3, from, res)
         NEG_ITER(currMax7, to, middle3, res)
         NEG_ITER(currMax8, to, middle2, res)
         NEG_ITER(currMax9, to, middle1, res)
         NEG_ITER(currMax10, to, from, res)
      }
   }
   if (res.m_sum > result.m_sum)
   {
      result.m_sum = res.m_sum;
      result.m_brColumn = (res.m_beginPtr - mat) / M;
      result.m_ulColumn = result.m_brColumn - res.m_width + 1;
      result.m_ulRow = (res.m_beginPtr - mat)  % M;
      result.m_brRow = (res.m_endPtr - mat)  % M;
   }
}

void calcColumnCombined(int * mat, int M, int fromIndex, int width1, int width2, int width3, int width4, int width5, ResultStruct & result)
{
   int* from = &mat[(fromIndex - 1) * M];
   int* middle1 = &mat[(fromIndex + width1 - 1) * M];
   int* middle2 = &mat[(fromIndex + width1 + width2 - 1) * M];
   int* middle3 = &mat[(fromIndex + width1 + width2 + width3 - 1) * M];
   int* middle4 = &mat[(fromIndex + width1 + width2 + width3 + width4 - 1) * M];
   int* to = &mat[(fromIndex + width1 + width2 + width3 + width4 + width5 - 1) * M];
   int* orig = to + M;
   TempResultStruct currMax1(middle1, middle1, width1, 0);
   TempResultStruct currMax2(middle2, middle2, width2, 0);
   TempResultStruct currMax3(middle2, middle2, width1 + width2, 0);
   TempResultStruct currMax4(middle3, middle3, width3, 0);
   TempResultStruct currMax5(middle3, middle3, width2 + width3, 0);
   TempResultStruct currMax6(middle3, middle3, width1 + width2 + width3, 0);
   TempResultStruct currMax7(middle4, middle4, width4, 0);
   TempResultStruct currMax8(middle4, middle4, width3 + width4, 0);
   TempResultStruct currMax9(middle4, middle4, width2 + width3 + width4, 0);
   TempResultStruct currMax10(middle4, middle4, width1 + width2 + width3 + width4, 0);
   TempResultStruct currMax11(to, to, width5, 0);
   TempResultStruct currMax12(to, to, width4 + width5, 0);
   TempResultStruct currMax13(to, to, width3 + width4 + width5, 0);
   TempResultStruct currMax14(to, to, width2 + width3 + width4 + width5, 0);
   TempResultStruct currMax15(to, to, width1 +width2 + width3 + width4 + width5, 0);
   TempResultStruct res(0, 0, 0, result.m_sum);
   if (res.m_sum > 0)
   {
      for (; to < orig; ++from, ++to, ++middle1, ++middle2, ++middle3, ++middle4)
      {
         POS_ITER(currMax1, middle1, from, res)
         POS_ITER(currMax2, middle2, middle1, res)
         POS_ITER(currMax3, middle2, from, res)
         POS_ITER(currMax4, middle3, middle2, res)
         POS_ITER(currMax5, middle3, middle1, res)
         POS_ITER(currMax6, middle3, from, res)
         POS_ITER(currMax7, middle4, middle3, res)
         POS_ITER(currMax8, middle4, middle2, res)
         POS_ITER(currMax9, middle4, middle1, res)
         POS_ITER(currMax10, middle4, from, res)
         POS_ITER(currMax11, to, middle4, res)
         POS_ITER(currMax12, to, middle3, res)
         POS_ITER(currMax13, to, middle2, res)
         POS_ITER(currMax14, to, middle1, res)
         POS_ITER(currMax15, to, from, res)
      }
   }
   else
   {
      for (; to < orig; ++from, ++to, ++middle1, ++middle2, ++middle3, ++middle4)
      {
         NEG_ITER(currMax1, middle1, from, res)
         NEG_ITER(currMax2, middle2, middle1, res)
         NEG_ITER(currMax3, middle2, from, res)
         NEG_ITER(currMax4, middle3, middle2, res)
         NEG_ITER(currMax5, middle3, middle1, res)
         NEG_ITER(currMax6, middle3, from, res)
         NEG_ITER(currMax7, middle4, middle3, res)
         NEG_ITER(currMax8, middle4, middle2, res)
         NEG_ITER(currMax9, middle4, middle1, res)
         NEG_ITER(currMax10, middle4, from, res)
         NEG_ITER(currMax11, to, middle4, res)
         NEG_ITER(currMax12, to, middle3, res)
         NEG_ITER(currMax13, to, middle2, res)
         NEG_ITER(currMax14, to, middle1, res)
         NEG_ITER(currMax15, to, from, res)
      }
   }
   if (res.m_sum > result.m_sum)
   {
      result.m_sum = res.m_sum;
      result.m_brColumn = (res.m_beginPtr - mat) / M;
      result.m_ulColumn = result.m_brColumn - res.m_width + 1;
      result.m_ulRow = (res.m_beginPtr - mat)  % M;
      result.m_brRow = (res.m_endPtr - mat)  % M;
   }
}

void calcColumnCombined(int * mat, int M, int fromIndex, int width1, int width2, int width3, int width4, int width5, int width6, ResultStruct & result)
{
   int* from = &mat[(fromIndex - 1) * M];
   int* middle1 = &mat[(fromIndex + width1 - 1) * M];
   int* middle2 = &mat[(fromIndex + width1 + width2 - 1) * M];
   int* middle3 = &mat[(fromIndex + width1 + width2 + width3 - 1) * M];
   int* middle4 = &mat[(fromIndex + width1 + width2 + width3 + width4 - 1) * M];
   int* middle5 = &mat[(fromIndex + width1 + width2 + width3 + width4 + width5 - 1) * M];
   int* to = &mat[(fromIndex + width1 + width2 + width3 + width4 + width5 + width6 - 1) * M];
   int* orig = to + M;
   TempResultStruct currMax1(middle1, middle1, width1, 0);
   TempResultStruct currMax2(middle2, middle2, width2, 0);
   TempResultStruct currMax3(middle2, middle2, width1 + width2, 0);
   TempResultStruct currMax4(middle3, middle3, width3, 0);
   TempResultStruct currMax5(middle3, middle3, width2 + width3, 0);
   TempResultStruct currMax6(middle3, middle3, width1 + width2 + width3, 0);
   TempResultStruct currMax7(middle4, middle4, width4, 0);
   TempResultStruct currMax8(middle4, middle4, width3 + width4, 0);
   TempResultStruct currMax9(middle4, middle4, width2 + width3 + width4, 0);
   TempResultStruct currMax10(middle4, middle4, width1 + width2 + width3 + width4, 0);
   TempResultStruct currMax11(middle5, middle5, width5, 0);
   TempResultStruct currMax12(middle5, middle5, width4 + width5, 0);
   TempResultStruct currMax13(middle5, middle5, width3 + width4 + width5, 0);
   TempResultStruct currMax14(middle5, middle5, width2 + width3 + width4 + width5, 0);
   TempResultStruct currMax15(middle5, middle5, width1 +width2 + width3 + width4 + width5, 0);
   TempResultStruct currMax16(to, to, width6, 0);
   TempResultStruct currMax17(to, to, width5 + width6, 0);
   TempResultStruct currMax18(to, to, width4 + width5 + width6, 0);
   TempResultStruct currMax19(to, to, width3 + width4 + width5 + width6, 0);
   TempResultStruct currMax20(to, to, width2 + width3 + width4 + width5 + width6, 0);
   TempResultStruct currMax21(to, to, width1 +width2 + width3 + width4 + width5 + width6, 0);
   TempResultStruct res(0, 0, 0, result.m_sum);
   if (res.m_sum > 0)
   {
      for (; to < orig; ++from, ++to, ++middle1, ++middle2, ++middle3, ++middle4, ++middle5)
      {
         POS_ITER(currMax1, middle1, from, res)
         POS_ITER(currMax2, middle2, middle1, res)
         POS_ITER(currMax3, middle2, from, res)
         POS_ITER(currMax4, middle3, middle2, res)
         POS_ITER(currMax5, middle3, middle1, res)
         POS_ITER(currMax6, middle3, from, res)
         POS_ITER(currMax7, middle4, middle3, res)
         POS_ITER(currMax8, middle4, middle2, res)
         POS_ITER(currMax9, middle4, middle1, res)
         POS_ITER(currMax10, middle4, from, res)
         POS_ITER(currMax11, middle5, middle4, res)
         POS_ITER(currMax12, middle5, middle3, res)
         POS_ITER(currMax13, middle5, middle2, res)
         POS_ITER(currMax14, middle5, middle1, res)
         POS_ITER(currMax15, middle5, from, res)
         POS_ITER(currMax16, to, middle5, res)
         POS_ITER(currMax17, to, middle4, res)
         POS_ITER(currMax18, to, middle3, res)
         POS_ITER(currMax19, to, middle2, res)
         POS_ITER(currMax20, to, middle1, res)
         POS_ITER(currMax21, to, from, res)
      }
   }
   else
   {
      for (; to < orig; ++from, ++to, ++middle1, ++middle2, ++middle3, ++middle4, ++middle5)
      {
         NEG_ITER(currMax1, middle1, from, res)
         NEG_ITER(currMax2, middle2, middle1, res)
         NEG_ITER(currMax3, middle2, from, res)
         NEG_ITER(currMax4, middle3, middle2, res)
         NEG_ITER(currMax5, middle3, middle1, res)
         NEG_ITER(currMax6, middle3, from, res)
         NEG_ITER(currMax7, middle4, middle3, res)
         NEG_ITER(currMax8, middle4, middle2, res)
         NEG_ITER(currMax9, middle4, middle1, res)
         NEG_ITER(currMax10, middle4, from, res)
         NEG_ITER(currMax11, middle5, middle4, res)
         NEG_ITER(currMax12, middle5, middle3, res)
         NEG_ITER(currMax13, middle5, middle2, res)
         NEG_ITER(currMax14, middle5, middle1, res)
         NEG_ITER(currMax15, middle5, from, res)
         NEG_ITER(currMax16, to, middle5, res)
         NEG_ITER(currMax17, to, middle4, res)
         NEG_ITER(currMax18, to, middle3, res)
         NEG_ITER(currMax19, to, middle2, res)
         NEG_ITER(currMax20, to, middle1, res)
         NEG_ITER(currMax21, to, from, res)
      }
   }
   if (res.m_sum > result.m_sum)
   {
      result.m_sum = res.m_sum;
      result.m_brColumn = (res.m_beginPtr - mat) / M;
      result.m_ulColumn = result.m_brColumn - res.m_width + 1;
      result.m_ulRow = (res.m_beginPtr - mat)  % M;
      result.m_brRow = (res.m_endPtr - mat)  % M;
   }
}

void calcColumnCombined(int * mat, int M, int fromIndex, int width1, int width2, int width3, int width4, int width5, int width6, int width7, ResultStruct & result)
{
   int* from = &mat[(fromIndex - 1) * M];
   int* middle1 = &mat[(fromIndex + width1 - 1) * M];
   int* middle2 = &mat[(fromIndex + width1 + width2 - 1) * M];
   int* middle3 = &mat[(fromIndex + width1 + width2 + width3 - 1) * M];
   int* middle4 = &mat[(fromIndex + width1 + width2 + width3 + width4 - 1) * M];
   int* middle5 = &mat[(fromIndex + width1 + width2 + width3 + width4 + width5 - 1) * M];
   int* middle6 = &mat[(fromIndex + width1 + width2 + width3 + width4 + width5 + width6 - 1) * M];
   int* to = &mat[(fromIndex + width1 + width2 + width3 + width4 + width5 + width6 + width7 - 1) * M];
   int* orig = to + M;
   TempResultStruct currMax1(middle1, middle1, width1, 0);
   TempResultStruct currMax2(middle2, middle2, width2, 0);
   TempResultStruct currMax3(middle2, middle2, width1 + width2, 0);
   TempResultStruct currMax4(middle3, middle3, width3, 0);
   TempResultStruct currMax5(middle3, middle3, width2 + width3, 0);
   TempResultStruct currMax6(middle3, middle3, width1 + width2 + width3, 0);
   TempResultStruct currMax7(middle4, middle4, width4, 0);
   TempResultStruct currMax8(middle4, middle4, width3 + width4, 0);
   TempResultStruct currMax9(middle4, middle4, width2 + width3 + width4, 0);
   TempResultStruct currMax10(middle4, middle4, width1 + width2 + width3 + width4, 0);
   TempResultStruct currMax11(middle5, middle5, width5, 0);
   TempResultStruct currMax12(middle5, middle5, width4 + width5, 0);
   TempResultStruct currMax13(middle5, middle5, width3 + width4 + width5, 0);
   TempResultStruct currMax14(middle5, middle5, width2 + width3 + width4 + width5, 0);
   TempResultStruct currMax15(middle5, middle5, width1 +width2 + width3 + width4 + width5, 0);
   TempResultStruct currMax16(middle6, middle6, width6, 0);
   TempResultStruct currMax17(middle6, middle6, width5 + width6, 0);
   TempResultStruct currMax18(middle6, middle6, width4 + width5 + width6, 0);
   TempResultStruct currMax19(middle6, middle6, width3 + width4 + width5 + width6, 0);
   TempResultStruct currMax20(middle6, middle6, width2 + width3 + width4 + width5 + width6, 0);
   TempResultStruct currMax21(middle6, middle6, width1 +width2 + width3 + width4 + width5 + width6, 0);
   TempResultStruct currMax22(to, to, width7, 0);
   TempResultStruct currMax23(to, to, width6 + width7, 0);
   TempResultStruct currMax24(to, to, width5 + width6 + width7, 0);
   TempResultStruct currMax25(to, to, width4 + width5 + width6 + width7, 0);
   TempResultStruct currMax26(to, to, width3 + width4 + width5 + width6 + width7, 0);
   TempResultStruct currMax27(to, to, width2 + width3 + width4 + width5 + width6 + width7, 0);
   TempResultStruct currMax28(to, to, width1 +width2 + width3 + width4 + width5 + width6 + width7, 0);
   TempResultStruct res(0, 0, 0, result.m_sum);
   if (res.m_sum > 0)
   {
      for (; to < orig; ++from, ++to, ++middle1, ++middle2, ++middle3, ++middle4, ++middle5, ++middle6)
      {
         POS_ITER(currMax1, middle1, from, res)
            POS_ITER(currMax2, middle2, middle1, res)
            POS_ITER(currMax3, middle2, from, res)
            POS_ITER(currMax4, middle3, middle2, res)
            POS_ITER(currMax5, middle3, middle1, res)
            POS_ITER(currMax6, middle3, from, res)
            POS_ITER(currMax7, middle4, middle3, res)
            POS_ITER(currMax8, middle4, middle2, res)
            POS_ITER(currMax9, middle4, middle1, res)
            POS_ITER(currMax10, middle4, from, res)
            POS_ITER(currMax11, middle5, middle4, res)
            POS_ITER(currMax12, middle5, middle3, res)
            POS_ITER(currMax13, middle5, middle2, res)
            POS_ITER(currMax14, middle5, middle1, res)
            POS_ITER(currMax15, middle5, from, res)
            POS_ITER(currMax16, middle6, middle5, res)
            POS_ITER(currMax17, middle6, middle4, res)
            POS_ITER(currMax18, middle6, middle3, res)
            POS_ITER(currMax19, middle6, middle2, res)
            POS_ITER(currMax20, middle6, middle1, res)
            POS_ITER(currMax21, middle6, from, res)
            POS_ITER(currMax22, to, middle6, res)
            POS_ITER(currMax23, to, middle5, res)
            POS_ITER(currMax24, to, middle4, res)
            POS_ITER(currMax25, to, middle3, res)
            POS_ITER(currMax26, to, middle2, res)
            POS_ITER(currMax27, to, middle1, res)
            POS_ITER(currMax28, to, from, res)
      }
   }
   else
   {
      for (; to < orig; ++from, ++to, ++middle1, ++middle2, ++middle3, ++middle4, ++middle5, ++middle6)
      {
         NEG_ITER(currMax1, middle1, from, res)
            NEG_ITER(currMax2, middle2, middle1, res)
            NEG_ITER(currMax3, middle2, from, res)
            NEG_ITER(currMax4, middle3, middle2, res)
            NEG_ITER(currMax5, middle3, middle1, res)
            NEG_ITER(currMax6, middle3, from, res)
            NEG_ITER(currMax7, middle4, middle3, res)
            NEG_ITER(currMax8, middle4, middle2, res)
            NEG_ITER(currMax9, middle4, middle1, res)
            NEG_ITER(currMax10, middle4, from, res)
            NEG_ITER(currMax11, middle5, middle4, res)
            NEG_ITER(currMax12, middle5, middle3, res)
            NEG_ITER(currMax13, middle5, middle2, res)
            NEG_ITER(currMax14, middle5, middle1, res)
            NEG_ITER(currMax15, middle5, from, res)
            NEG_ITER(currMax16, middle6, middle5, res)
            NEG_ITER(currMax17, middle6, middle4, res)
            NEG_ITER(currMax18, middle6, middle3, res)
            NEG_ITER(currMax19, middle6, middle2, res)
            NEG_ITER(currMax20, middle6, middle1, res)
            NEG_ITER(currMax21, middle6, from, res)
            NEG_ITER(currMax22, to, middle6, res)
            NEG_ITER(currMax23, to, middle5, res)
            NEG_ITER(currMax24, to, middle4, res)
            NEG_ITER(currMax25, to, middle3, res)
            NEG_ITER(currMax26, to, middle2, res)
            NEG_ITER(currMax27, to, middle1, res)
            NEG_ITER(currMax28, to, from, res)
      }
   }
   if (res.m_sum > result.m_sum)
   {
      result.m_sum = res.m_sum;
      result.m_brColumn = (res.m_beginPtr - mat) / M;
      result.m_ulColumn = result.m_brColumn - res.m_width + 1;
      result.m_ulRow = (res.m_beginPtr - mat)  % M;
      result.m_brRow = (res.m_endPtr - mat)  % M;
   }
}


void calcColumnCombined(int * mat, int M, int fromIndex, int width1, int width2, int width3, int width4, int width5, int width6, int width7, int width8, ResultStruct & result)
{
   int* from = &mat[(fromIndex - 1) * M];
   int* middle1 = &mat[(fromIndex + width1 - 1) * M];
   int* middle2 = &mat[(fromIndex + width1 + width2 - 1) * M];
   int* middle3 = &mat[(fromIndex + width1 + width2 + width3 - 1) * M];
   int* middle4 = &mat[(fromIndex + width1 + width2 + width3 + width4 - 1) * M];
   int* middle5 = &mat[(fromIndex + width1 + width2 + width3 + width4 + width5 - 1) * M];
   int* middle6 = &mat[(fromIndex + width1 + width2 + width3 + width4 + width5 + width6 - 1) * M];
   int* middle7 = &mat[(fromIndex + width1 + width2 + width3 + width4 + width5 + width6 + width7 - 1) * M];
   int* to = &mat[(fromIndex + width1 + width2 + width3 + width4 + width5 + width6 + width7 + width8 - 1) * M];
   int* orig = to + M;
   TempResultStruct currMax1(middle1, middle1, width1, 0);
   TempResultStruct currMax2(middle2, middle2, width2, 0);
   TempResultStruct currMax3(middle2, middle2, width1 + width2, 0);
   TempResultStruct currMax4(middle3, middle3, width3, 0);
   TempResultStruct currMax5(middle3, middle3, width2 + width3, 0);
   TempResultStruct currMax6(middle3, middle3, width1 + width2 + width3, 0);
   TempResultStruct currMax7(middle4, middle4, width4, 0);
   TempResultStruct currMax8(middle4, middle4, width3 + width4, 0);
   TempResultStruct currMax9(middle4, middle4, width2 + width3 + width4, 0);
   TempResultStruct currMax10(middle4, middle4, width1 + width2 + width3 + width4, 0);
   TempResultStruct currMax11(middle5, middle5, width5, 0);
   TempResultStruct currMax12(middle5, middle5, width4 + width5, 0);
   TempResultStruct currMax13(middle5, middle5, width3 + width4 + width5, 0);
   TempResultStruct currMax14(middle5, middle5, width2 + width3 + width4 + width5, 0);
   TempResultStruct currMax15(middle5, middle5, width1 +width2 + width3 + width4 + width5, 0);
   TempResultStruct currMax16(middle6, middle6, width6, 0);
   TempResultStruct currMax17(middle6, middle6, width5 + width6, 0);
   TempResultStruct currMax18(middle6, middle6, width4 + width5 + width6, 0);
   TempResultStruct currMax19(middle6, middle6, width3 + width4 + width5 + width6, 0);
   TempResultStruct currMax20(middle6, middle6, width2 + width3 + width4 + width5 + width6, 0);
   TempResultStruct currMax21(middle6, middle6, width1 +width2 + width3 + width4 + width5 + width6, 0);
   TempResultStruct currMax22(middle7, middle7, width7, 0);
   TempResultStruct currMax23(middle7, middle7, width6 + width7, 0);
   TempResultStruct currMax24(middle7, middle7, width5 + width6 + width7, 0);
   TempResultStruct currMax25(middle7, middle7, width4 + width5 + width6 + width7, 0);
   TempResultStruct currMax26(middle7, middle7, width3 + width4 + width5 + width6 + width7, 0);
   TempResultStruct currMax27(middle7, middle7, width2 + width3 + width4 + width5 + width6 + width7, 0);
   TempResultStruct currMax28(middle7, middle7, width1 +width2 + width3 + width4 + width5 + width6 + width7, 0);
   TempResultStruct currMax29(to, to, width8, 0);
   TempResultStruct currMax30(to, to, width7 + width8, 0);
   TempResultStruct currMax31(to, to, width6 + width7 + width8, 0);
   TempResultStruct currMax32(to, to, width5 + width6 + width7 + width8, 0);
   TempResultStruct currMax33(to, to, width4 + width5 + width6 + width7 + width8, 0);
   TempResultStruct currMax34(to, to, width3 + width4 + width5 + width6 + width7 + width8, 0);
   TempResultStruct currMax35(to, to, width2 + width3 + width4 + width5 + width6 + width7 + width8, 0);
   TempResultStruct currMax36(to, to, width1 +width2 + width3 + width4 + width5 + width6 + width7 + width8, 0);
   TempResultStruct res(0, 0, 0, result.m_sum);
   if (res.m_sum > 0)
   {
      for (; to < orig; ++from, ++to, ++middle1, ++middle2, ++middle3, ++middle4, ++middle5, ++middle6, ++middle7)
      {
         POS_ITER(currMax1, middle1, from, res)
            POS_ITER(currMax2, middle2, middle1, res)
            POS_ITER(currMax3, middle2, from, res)
            POS_ITER(currMax4, middle3, middle2, res)
            POS_ITER(currMax5, middle3, middle1, res)
            POS_ITER(currMax6, middle3, from, res)
            POS_ITER(currMax7, middle4, middle3, res)
            POS_ITER(currMax8, middle4, middle2, res)
            POS_ITER(currMax9, middle4, middle1, res)
            POS_ITER(currMax10, middle4, from, res)
            POS_ITER(currMax11, middle5, middle4, res)
            POS_ITER(currMax12, middle5, middle3, res)
            POS_ITER(currMax13, middle5, middle2, res)
            POS_ITER(currMax14, middle5, middle1, res)
            POS_ITER(currMax15, middle5, from, res)
            POS_ITER(currMax16, middle6, middle5, res)
            POS_ITER(currMax17, middle6, middle4, res)
            POS_ITER(currMax18, middle6, middle3, res)
            POS_ITER(currMax19, middle6, middle2, res)
            POS_ITER(currMax20, middle6, middle1, res)
            POS_ITER(currMax21, middle6, from, res)
            POS_ITER(currMax22, middle7, middle6, res)
            POS_ITER(currMax23, middle7, middle5, res)
            POS_ITER(currMax24, middle7, middle4, res)
            POS_ITER(currMax25, middle7, middle3, res)
            POS_ITER(currMax26, middle7, middle2, res)
            POS_ITER(currMax27, middle7, middle1, res)
            POS_ITER(currMax28, middle7, from, res)
            POS_ITER(currMax29, to, middle7, res)
            POS_ITER(currMax30, to, middle6, res)
            POS_ITER(currMax31, to, middle5, res)
            POS_ITER(currMax32, to, middle4, res)
            POS_ITER(currMax33, to, middle3, res)
            POS_ITER(currMax34, to, middle2, res)
            POS_ITER(currMax35, to, middle1, res)
            POS_ITER(currMax36, to, from, res)
      }
   }
   else
   {
      for (; to < orig; ++from, ++to, ++middle1, ++middle2, ++middle3, ++middle4, ++middle5, ++middle6, ++middle7)
      {
         NEG_ITER(currMax1, middle1, from, res)
            NEG_ITER(currMax2, middle2, middle1, res)
            NEG_ITER(currMax3, middle2, from, res)
            NEG_ITER(currMax4, middle3, middle2, res)
            NEG_ITER(currMax5, middle3, middle1, res)
            NEG_ITER(currMax6, middle3, from, res)
            NEG_ITER(currMax7, middle4, middle3, res)
            NEG_ITER(currMax8, middle4, middle2, res)
            NEG_ITER(currMax9, middle4, middle1, res)
            NEG_ITER(currMax10, middle4, from, res)
            NEG_ITER(currMax11, middle5, middle4, res)
            NEG_ITER(currMax12, middle5, middle3, res)
            NEG_ITER(currMax13, middle5, middle2, res)
            NEG_ITER(currMax14, middle5, middle1, res)
            NEG_ITER(currMax15, middle5, from, res)
            NEG_ITER(currMax16, middle6, middle5, res)
            NEG_ITER(currMax17, middle6, middle4, res)
            NEG_ITER(currMax18, middle6, middle3, res)
            NEG_ITER(currMax19, middle6, middle2, res)
            NEG_ITER(currMax20, middle6, middle1, res)
            NEG_ITER(currMax21, middle6, from, res)
            NEG_ITER(currMax22, middle7, middle6, res)
            NEG_ITER(currMax23, middle7, middle5, res)
            NEG_ITER(currMax24, middle7, middle4, res)
            NEG_ITER(currMax25, middle7, middle3, res)
            NEG_ITER(currMax26, middle7, middle2, res)
            NEG_ITER(currMax27, middle7, middle1, res)
            NEG_ITER(currMax28, middle7, from, res)
            NEG_ITER(currMax29, to, middle7, res)
            NEG_ITER(currMax30, to, middle6, res)
            NEG_ITER(currMax31, to, middle5, res)
            NEG_ITER(currMax32, to, middle4, res)
            NEG_ITER(currMax33, to, middle3, res)
            NEG_ITER(currMax34, to, middle2, res)
            NEG_ITER(currMax35, to, middle1, res)
            NEG_ITER(currMax36, to, from, res)
      }
   }
   if (res.m_sum > result.m_sum)
   {
      result.m_sum = res.m_sum;
      result.m_brColumn = (res.m_beginPtr - mat) / M;
      result.m_ulColumn = result.m_brColumn - res.m_width + 1;
      result.m_ulRow = (res.m_beginPtr - mat)  % M;
      result.m_brRow = (res.m_endPtr - mat)  % M;
   }
}




void prepareCombined(int * mat, int M, int width1, int width2, ResultStruct & res)
{
    for (int i = 0; i < width1; ++i)
    {
        calcColumn(mat, M, i, width2, res);
    }
}

void prepareCombined(int * mat, int M, int width1, int width2, int width3, ResultStruct & res)
{
    prepareCombined(mat, M, width2, width3, res);
    for (int i = 0; i < width1; ++i)
    {
         calcColumnCombined(mat, M, i, width2, width3, res);
    }
}

void prepareCombined(int * mat, int M, int width1, int width2, int width3, int width4, ResultStruct & res)
{
   prepareCombined(mat, M, width2, width3, width4, res);
   for (int i = 0; i < width1; ++i)
   {
      calcColumnCombined(mat, M, i, width2, width3, width4, res);
   }
}

void prepareCombined(int * mat, int M, int width1, int width2, int width3, int width4, int width5, ResultStruct & res)
{
   prepareCombined(mat, M, width2, width3, width4, width5, res);
   for (int i = 0; i < width1; ++i)
   {
      calcColumnCombined(mat, M, i, width2, width3, width4, width5, res);
   }
}

void prepareCombined(int * mat, int M, int width1, int width2, int width3, int width4, int width5, int width6, ResultStruct & res)
{
   prepareCombined(mat, M, width2, width3, width4, width5, width6, res);
   for (int i = 0; i < width1; ++i)
   {
      calcColumnCombined(mat, M, i, width2, width3, width4, width5, width6, res);
   }
}

void prepareCombined(int * mat, int M, int width1, int width2, int width3, int width4, int width5, int width6, int width7, ResultStruct & res)
{
   prepareCombined(mat, M, width2, width3, width4, width5, width6, width7, res);
   for (int i = 0; i < width1; ++i)
   {
      calcColumnCombined(mat, M, i, width2, width3, width4, width5, width6, width7, res);
   }
}

void prepareCombined(int * mat, int M, int width1, int width2, int width3, int width4, int width5, int width6, int width7, int width8, ResultStruct & res)
{
   prepareCombined(mat, M, width2, width3, width4, width5, width6, width7, width8, res);
   for (int i = 0; i < width1; ++i)
   {
      calcColumnCombined(mat, M, i, width2, width3, width4, width5, width6, width7, width8, res);
   }
}

void finalizeCombined(int * mat, int M, int N, int width1, int width2, ResultStruct & res)
{
   for (int i = N - width2 - width1 + 1; i < N - width1 + 1; ++i)
   {
       calcColumn(mat, M, i, width1, res);
   }
}

void finalizeCombined(int * mat, int M, int N, int width1, int width2, int width3, ResultStruct & res)
{
   for (int i = N - width3 - width2 - width1 + 1; i < N - width1 - width2 + 1; ++i)
   {
       calcColumnCombined(mat, M, i, width1, width2, res);
   }
   finalizeCombined(mat, M, N, width1, width2, res);
}

void finalizeCombined(int * mat, int M, int N, int width1, int width2, int width3, int width4, ResultStruct & res)
{
   for (int i = N - width4 - width3 - width2 - width1 + 1; i < N - width1 - width2 - width3 + 1; ++i)
   {
      calcColumnCombined(mat, M, i, width1, width2, width3, res);
   }
   finalizeCombined(mat, M, N, width1, width2, width3, res);
}

void finalizeCombined(int * mat, int M, int N, int width1, int width2, int width3, int width4, int width5, ResultStruct & res)
{
   for (int i = N - width5 - width4 - width3 - width2 - width1 + 1; i < N - width1 - width2 - width3 - width4 + 1; ++i)
   {
      calcColumnCombined(mat, M, i, width1, width2, width3, width4, res);
   }
   finalizeCombined(mat, M, N, width1, width2, width3, width4, res);
}

void finalizeCombined(int * mat, int M, int N, int width1, int width2, int width3, int width4, int width5, int width6, ResultStruct & res)
{
   for (int i = N - width6 - width5 - width4 - width3 - width2 - width1 + 1; i < N - width1 - width2 - width3 - width4 - width5 + 1; ++i)
   {
      calcColumnCombined(mat, M, i, width1, width2, width3, width4, width5, res);
   }
   finalizeCombined(mat, M, N, width1, width2, width3, width4, width5, res);
}

void finalizeCombined(int * mat, int M, int N, int width1, int width2, int width3, int width4, int width5, int width6, int width7, ResultStruct & res)
{
   for (int i = N - width7 - width6 - width5 - width4 - width3 - width2 - width1 + 1; i < N - width1 - width2 - width3 - width4 - width5 - width6 + 1; ++i)
   {
      calcColumnCombined(mat, M, i, width1, width2, width3, width4, width5, width6, res);
   }
   finalizeCombined(mat, M, N, width1, width2, width3, width4, width5, width6, res);
}


void finalizeCombined(int * mat, int M, int N, int width1, int width2, int width3, int width4, int width5, int width6, int width7, int width8, ResultStruct & res)
{
   for (int i = N - width8 -width7 - width6 - width5 - width4 - width3 - width2 - width1 + 1; i < N - width1 - width2 - width3 - width4 - width5 - width6 - width7 + 1; ++i)
   {
      calcColumnCombined(mat, M, i, width1, width2, width3, width4, width5, width6, width7, res);
   }
   finalizeCombined(mat, M, N, width1, width2, width3, width4, width5, width6, width7, res);
}

//TASK1
void verticalTask(int threadNumber, Task& task)
{
    int N = testCases[task.m_testCase].N;
    int M = testCases[task.m_testCase].M;
    ResultStruct& res = threadsContext[threadNumber].m_testCasesResults[task.m_testCase];
    int * mat = &matrixes[testCases[task.m_testCase].matrixNumber][0] + M;// "zero" column
    int taskInc = 0;
    switch (task.m_columnTaskType)
    {
    case Task::COMBINED:
    {
        switch (task.m_columnsCount)
        {
        case 2:
        {
            taskInc = 3;
            int width1 = task.m_columns[0];
            int width2 = task.m_columns[1];
            prepareCombined(mat, M, width1, width2, res);
            for (int i = 0; i < N - width1 - width2 + 1; ++i)
            {
               calcColumnCombined(mat, M, i, width1, width2, res);
            }
            finalizeCombined(mat, M, N, width1, width2, res);
            break;
        }
        case 3:
        {
            taskInc = 6;
            int width1 = task.m_columns[0];
            int width2 = task.m_columns[1];
            int width3 = task.m_columns[2];
            prepareCombined(mat, M, width1, width2, width3, res);
            for (int i = 0; i < N - width1 - width2 - width3 + 1; ++i)
            {
               calcColumnCombined(mat, M, i, width1, width2, width3, res);
            }
            finalizeCombined(mat, M, N, width1, width2, width3, res);
            break;
        }
        case 4:
           {
              taskInc = 10;
              int width1 = task.m_columns[0];
              int width2 = task.m_columns[1];
              int width3 = task.m_columns[2];
              int width4 = task.m_columns[3];
              prepareCombined(mat, M, width1, width2, width3, width4, res);
              for (int i = 0; i < N - width1 - width2 - width3 - width4 + 1; ++i)
              {
                 calcColumnCombined(mat, M, i, width1, width2, width3, width4, res);
              }
              finalizeCombined(mat, M, N, width1, width2, width3, width4, res);
              break;
           }
        case 5:
           {
              taskInc = 15;
              int width1 = task.m_columns[0];
              int width2 = task.m_columns[1];
              int width3 = task.m_columns[2];
              int width4 = task.m_columns[3];
              int width5 = task.m_columns[4];
              prepareCombined(mat, M, width1, width2, width3, width4, width5, res);
              for (int i = 0; i < N - width1 - width2 - width3 - width4 - width5 + 1; ++i)
              {
                 calcColumnCombined(mat, M, i, width1, width2, width3, width4, width5, res);
              }
              finalizeCombined(mat, M, N, width1, width2, width3, width4, width5, res);
              break;
           }
        case 6:
           {
              taskInc = 21;
              int width1 = task.m_columns[0];
              int width2 = task.m_columns[1];
              int width3 = task.m_columns[2];
              int width4 = task.m_columns[3];
              int width5 = task.m_columns[4];
              int width6 = task.m_columns[5];
              prepareCombined(mat, M, width1, width2, width3, width4, width5, width6, res);
              for (int i = 0; i < N - width1 - width2 - width3 - width4 - width5 - width6 + 1; ++i)
              {
                 calcColumnCombined(mat, M, i, width1, width2, width3, width4, width5, width6, res);
              }
              finalizeCombined(mat, M, N, width1, width2, width3, width4, width5, width6, res);
              break;
           }
        case 7:
           {
              taskInc = 28;
              int width1 = task.m_columns[0];
              int width2 = task.m_columns[1];
              int width3 = task.m_columns[2];
              int width4 = task.m_columns[3];
              int width5 = task.m_columns[4];
              int width6 = task.m_columns[5];
              int width7 = task.m_columns[6];
              prepareCombined(mat, M, width1, width2, width3, width4, width5, width6, width7, res);
              for (int i = 0; i < N - width1 - width2 - width3 - width4 - width5 - width6 - width7 + 1; ++i)
              {
                 calcColumnCombined(mat, M, i, width1, width2, width3, width4, width5, width6, width7, res);
              }
              finalizeCombined(mat, M, N, width1, width2, width3, width4, width5, width6, width7, res);
              break;
           }
        case 8:
           {
              taskInc = 36;
              int width1 = task.m_columns[0];
              int width2 = task.m_columns[1];
              int width3 = task.m_columns[2];
              int width4 = task.m_columns[3];
              int width5 = task.m_columns[4];
              int width6 = task.m_columns[5];
              int width7 = task.m_columns[6];
              int width8 = task.m_columns[7];
              prepareCombined(mat, M, width1, width2, width3, width4, width5, width6, width7, width8, res);
              for (int i = 0; i < N - width1 - width2 - width3 - width4 - width5 - width6 - width7 - width8 + 1; ++i)
              {
                 calcColumnCombined(mat, M, i, width1, width2, width3, width4, width5, width6, width7, width8, res);
              }
              finalizeCombined(mat, M, N, width1, width2, width3, width4, width5, width6, width7, width8, res);
              break;
           }
        };
        
        break;
    }
    case Task::PAIRED:
    {
        int width1 = task.m_columns[0];
        int width2 = task.m_columns[1];
        int width3 = task.m_columns[2];
        int width4 = task.m_columns[3];
        int width5 = task.m_columns[4];
        int width6 = task.m_columns[5];
        int width7 = task.m_columns[6];
        taskInc = 7;
        for (int i = 0; i < N - width7 + 1; ++i)
        {
           calcColumnPaired(mat, M, i, width1, width2, width3, width4, width5, width6, width7, res);
        }
        for (int i = N - width7 + 1; i < N - width6 + 1; ++i)
        {
           calcColumnPaired(mat, M, i, width1, width2, width3, width4, width5, width6, res);
        }
        for (int i = N - width6 + 1; i < N - width5 + 1; ++i)
        {
           calcColumnPaired(mat, M, i, width1, width2, width3, width4, width5, res);
        }
        for (int i = N - width5 + 1; i < N - width4 + 1; ++i)
        {
           calcColumnPaired(mat, M, i, width1, width2, width3, width4, res);
        }
        for (int i = N - width4 + 1; i < N - width3 + 1; ++i)
        {
           calcColumnPaired(mat, M, i, width1, width2, width3, res);
        }
        for (int i = N - width3 + 1; i < N - width2 + 1; ++i)
        {
           calcColumnPaired(mat, M, i, width1, width2, res);
        }
        for (int i = N - width2 + 1; i < N - width1 + 1; ++i)
        {
           calcColumn(mat, M, i, width1, res);
        }
        break;
    }
    case Task::SINGLE:
    {
        taskInc = 1;
        int width1 = task.m_columns[0];
        for (int i = 0; i < N - width1 + 1; ++i)
        {
           calcColumn(mat, M, i, width1, res);
        }
        break;
    }
    };
    pthread_spin_lock(&testCases[task.m_testCase].m_lock);
    testCases[task.m_testCase].countedColumnSet += taskInc;
    if (testCases[task.m_testCase].countedColumnSet < N)
    {
        pthread_spin_unlock(&testCases[task.m_testCase].m_lock);
        return;
    }
    pthread_spin_unlock(&testCases[task.m_testCase].m_lock);
    pthread_spin_lock(&taskCountDoneLock);
    ++casesDone;
    if (casesDone == T)
    {
        workDone = true;
        pthread_spin_unlock(&taskCountDoneLock);
    }
    pthread_spin_unlock(&taskCountDoneLock);
    Task newTask;
    newTask.m_func = &initialTask;
    newTask.m_columnsCount = testCases[task.m_testCase].matrixNumber;
    threadsContext[threadNumber].m_tasks.push(newTask);
}

inline void createCombinedColumnTask(int threadNumber, int testCase, int* busy, int N, int groupPower)
{
   int founded = 0;
   short p[10] = {0};
   int sum = 0;
   Task newTask;
   newTask.m_func = &verticalTask;
   newTask.m_testCase = testCase;
   newTask.m_columnTaskType = Task::COMBINED;
   for (int i = 1; (i <= N) && (sum + i <= N); ++i)
   {
      if (busy[i] == 1) continue;
      bool sut = true;
      for (int p1 = 0; (p1 < founded - 1) && (sut); ++p1)
      {
          int ps = p[p1];
          for (int p2 = p1 + 1; (p2 < founded) && (sut); ++p2)
          {
              ps += p[p2];
              if (ps == i)
              {
                  sut = false;
              }
          }
      }
      if (!sut) continue;
      int ps = i;
      int j;
      for (j = founded - 1; (j >= 0) && (sut); --j)
      {
          if (busy[ps + p[j]] == 1)
          {
              sut = false;
              break;
          }
          ps += p[j];
      }
      if (!sut) continue;
      p[founded] = i;
      ++founded;
      sum += i;
      if (founded == groupPower)
      {
         memset(&newTask.m_columns[0], 0, sizeof(newTask.m_columns));
         newTask.m_columnsCount = groupPower;
         memcpy(&newTask.m_columns[0], &p[0], sizeof(newTask.m_columns[0]) * groupPower);
         threadsContext[threadNumber].m_tasks.push(newTask);
         for (int j = 0; j < groupPower; ++j)
         {
            busy[p[j]] = 1;
         }
         for (int p1 = 0; p1 < founded - 1; ++p1)
         {
            int ps = p[p1];
            for (int p2 = p1 + 1; p2 < founded; ++p2)
            {
               ps += p[p2];
               busy[ps] = 1;
            }
         }
         founded = 0;
         sum = 0;
      }
   }
}


inline void createPairedColumnTask(int threadNumber, int testCase, int* busy, int N, int groupPower)
{
   int founded = 0;
   short p[10] = {0};
   Task newTask;
   newTask.m_func = &verticalTask;
   newTask.m_testCase = testCase;
   newTask.m_columnTaskType = Task::PAIRED;
   for (int i = 1; i <= N; ++i)
   {
      if (busy[i] == 1) continue;
      p[founded] = i;
      ++founded;
      if (founded == groupPower)
      {
         memset(&newTask.m_columns[0], 0, sizeof(newTask.m_columns));
         newTask.m_columnsCount = groupPower;
         memcpy(&newTask.m_columns[0], &p[0], sizeof(short) * groupPower);
         threadsContext[threadNumber].m_tasks.push(newTask);
         for (int j = 0; j < groupPower; ++j)
         {
            busy[p[j]] = 1;
         }
         founded = 0;
      }
   }
   newTask.m_columnTaskType = Task::SINGLE;
   newTask.m_columnsCount = 1;
   for (int i = 0; i < founded; ++i)
   {
      newTask.m_columns[0] = p[i];
      threadsContext[threadNumber].m_tasks.push(newTask);  
   }
}

//TASK 0
void fillMatrixTask(int threadNumber, Task& task)
{
    int *matrix = matrixes[testCases[task.m_testCase].matrixNumber];
    testCases[task.m_testCase].isTrans = testCases[task.m_testCase].M < testCases[task.m_testCase].N;
    bool isTrans = testCases[task.m_testCase].isTrans;
    if (isTrans)
    {
        int tmp = testCases[task.m_testCase].M;
        testCases[task.m_testCase].M = testCases[task.m_testCase].N;
        testCases[task.m_testCase].N = tmp;
    }
    memset(matrix, 0, testCases[task.m_testCase].M * sizeof(int));
    matrix += testCases[task.m_testCase].M;

    int a = testCases[task.m_testCase].a;
    int b = testCases[task.m_testCase].b;
    int m = testCases[task.m_testCase].m;

    int M = testCases[task.m_testCase].M;
    int N = testCases[task.m_testCase].N;

    int dstSize = M * N;
    int seed = testCases[task.m_testCase].seed0;
    int i, j;
    long long sum = 0;
    int mean, remainder;

    long long rowSum;
        
    if (isTrans)
    {
        for (j = 0; j < M; ++j)
        {
            seed = (a * seed + b) % m;
            matrix[j] = seed;
            sum += seed;
        }

        for (i = 1; i < N; ++i)
        {
            for (j = 0; j < M; ++j)
            {
                seed = (a * seed + b) % m;
                matrix[i * M + j] = matrix[(i-1) * M + j] + seed;
                sum += seed;
            }
        }

    }
    else
    {
        for (i = 0; i < M; ++i)
        {
            rowSum = 0;
            for (j = 0; j < N; ++j)
            {
                seed = (a * seed + b) % m;
                rowSum += seed;
                matrix[j * M + i] = rowSum;
                sum += seed;
            }
        }
    }
    /* calculate the mean value. Avoid float logic when making rounding. */
    mean = (int) (sum / (long long) dstSize); /* updated line */
    remainder = (int) (sum % (long long) dstSize); /* updated line */
    mean += (remainder * 2 > (signed) dstSize) ? (1) : (0); /* updated line */
    
    for (j = 0; j < N; ++j)
    {
        for (i = 0; i < M; ++i)
        {

            {matrix[j * M + i] -= mean * (j + 1);}
        }
    }
    int busy[20001] = {0};
    createCombinedColumnTask(threadNumber, task.m_testCase, busy, N, 8);
    createCombinedColumnTask(threadNumber, task.m_testCase, busy, N, 7);
    createCombinedColumnTask(threadNumber, task.m_testCase, busy, N, 6);
    createCombinedColumnTask(threadNumber, task.m_testCase, busy, N, 5);
    createCombinedColumnTask(threadNumber, task.m_testCase, busy, N, 4);
    //createCombinedColumnTask(threadNumber, task.m_testCase, busy, N, 3);    
    //createCombinedColumnTask(threadNumber, task.m_testCase, busy, N, 2);    
    createPairedColumnTask(threadNumber, task.m_testCase, busy, N, 7);
}

// TASK -1
void initialTask(int threadNumber, Task& task)
{
    pthread_spin_lock(&taskCountLock);
    if (casesLaunched == T)
    {
        pthread_spin_unlock(&taskCountLock);
        return;
    }
    Task nextTask;
    nextTask.m_func = &fillMatrixTask;
    nextTask.m_testCase = casesLaunched;
    ++casesLaunched;
    pthread_spin_unlock(&taskCountLock);
    testCases[nextTask.m_testCase].matrixNumber = task.m_columnsCount;;
    if (matrixes[testCases[nextTask.m_testCase].matrixNumber] == 0)
    {
        matrixes[testCases[nextTask.m_testCase].matrixNumber] = new int[DATA_SIZE];
    }
    testCases[nextTask.m_testCase].countedColumnSet = 0;
    threadsContext[threadNumber].m_tasks.push(nextTask);
}

bool getTask(int threadNumber, Task& task)
{
    if (threadsContext[threadNumber].m_tasks.pop(task))
    {
        return true;
    }
    //this can be optimized if we first try to steal from thread on same processor
    int i = (threadNumber + 1) % numCores;
    while (!workDone)
    {
        if (threadsContext[i].m_tasks.pop(task))
        {
            return true;
        }
        i = (i + 1) % numCores;
    }
    return false;
}

void* threadRoutine(void* params)
{
    int threadNumber = *((int*)params);
    Task task;
    while (!workDone)
    {
        if (getTask(threadNumber, task))
        {
            task.m_func(threadNumber, task);
        }
    }
    return 0;
}

int main(int argc, char * argv[])
{
    int nums[MAX_THREAD_NUMBER];
    for (int i = 0; i< MAX_THREAD_NUMBER; ++i)
    {
        nums[i] = i;
    }
    pthread_t thrd[MAX_THREAD_NUMBER];
#if defined(WIN32) || defined(WIN64)
    LARGE_INTEGER fr, bt, et;
    QueryPerformanceFrequency(&fr);
    QueryPerformanceCounter(&bt);
#endif
    numCores = GetNumberOfCores();
#if defined(_DEBUG)
    numCores = 4;
#endif
    //current thread is tread number 0;
    for (int i = 1; i < numCores; ++i)
    {
        threadsContext[i].m_number = i;
        pthread_create(&thrd[i], 0, &threadRoutine, &nums[i]);
    }
    if (argc > 1 )
    {
        freopen(argv[1], "rt", stdin);
        freopen(argv[2], "w", stdout);
    } else
    {
        freopen("input.txt", "rt", stdin);
        freopen("output.txt", "w", stdout);
    }
    pthread_spin_init(&taskCountLock, 0);
    pthread_spin_init(&taskCountDoneLock, 0);
    scanf("%d", &T);
    for (int t = 0; t < T; ++t)
    {
        scanf("%d%d%d%d%d%d", &testCases[t].M, &testCases[t].N, &testCases[t].seed0, &testCases[t].a, &testCases[t].b, &testCases[t].m);
        pthread_spin_init(&testCases[t].m_lock, 0);
    }
    Task initTask;
    initTask.m_func = &initialTask;
    if (numCores > 10)
    {
        //its probably some big computer with a lot of memory
        concurrentCases = MAX_CONCURRENT_CASES;
    }
    for (int i = 0; i < concurrentCases; ++i)
    {
        //matrixes[i] = new int[DATA_SIZE];
        initTask.m_columnsCount = i;
        threadsContext[i].m_tasks.push(initTask);
    }
    threadRoutine(&nums[0]);
    for (int i = 0; i < T; ++i)
    {
        int maxN = 0;
        for (int j = 1; j < numCores; ++j)
        {
            if (threadsContext[j].m_testCasesResults[i].m_sum > threadsContext[maxN].m_testCasesResults[i].m_sum)
            {
                maxN = j;
            }
        }
        const ResultStruct &res = threadsContext[maxN].m_testCasesResults[i];
        if (testCases[i].isTrans)
        {
            printf("Case #%d: %d %d %d %d %d %d\n",
              i + 1,
              res.m_ulColumn,
              res.m_ulRow,
              res.m_brColumn,
              res.m_brRow,
              res.m_sum,
              (res.m_brColumn - res.m_ulColumn + 1) * (res.m_brRow - res.m_ulRow + 1));
        }
        else
        {
           printf("Case #%d: %d %d %d %d %d %d\n",
                   i + 1,
                   res.m_ulRow,
                   res.m_ulColumn,
                   res.m_brRow,
                   res.m_brColumn,
                   res.m_sum,
                   (res.m_brColumn - res.m_ulColumn + 1) * (res.m_brRow - res.m_ulRow + 1));
        }
    }
#if defined(WIN32) || defined(WIN64)
    QueryPerformanceCounter(&et);
    printf("time = %ds",(et.QuadPart - bt.QuadPart) / fr.QuadPart);
#endif
    for (int i=0; i < concurrentCases; ++i)
    {
        if (matrixes[i] != 0)
        {
            delete[] matrixes[i];
        }
    }
    return 0;
} // int main(int argc, char * argv[])
